iT邦幫忙

2024 iThome 鐵人賽

DAY 4
1
JavaScript

TypeScript 初學者也能看的學習指南系列 第 4

TypeScript 初學者也能看的學習指南 04 - 型別系統: 型別註釋 & 型別推斷

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240913/20149362ObpTEuBHmR.png

型別系統(Type System)是 TypeScript 提供的核心功能,它建立起了型別的宇宙
本篇要來介紹型別系統中在基本不過的概念 -「型別註釋」、「型別推斷

在進入正題之前,先來回憶一下 JavaScript 有哪些型別呢?

原始型別 物件型別
String Array
Number Object
Boolean Function
Null Date
Undefined RegExp
BigInt Error
Symbol Map, Set, WeakMap, WeakSet

💡 有別於 JS 的型別是固定的。TypeScript 型別系統有個很強大的功能是可擴充型別,也就是可以自訂義型別,像是 Interface(介面), Enum(枚舉), Generics(泛型) ... 等。後續的章節會逐一介紹

TypeScript 的型別系統裡除了涵蓋上方提到的原始型別外,還包含了非常多~~的型別和定義方式,等等要講的 型別註釋 (Type Annotations) 也是其中之一
如下圖整理
https://ithelp.ithome.com.tw/upload/images/20240914/20149362O1ZHmz4pe9.png


型別註釋(Type Annotations)

定義:明確指定變數或參數的型別。TS 的型別註釋是在變數或參數後用冒號 (:) 表示,例如:

: string
: boolean
: number
: any
: void
: [string, number]
: number[]
// ...略

使用時機:

  • 欲提高函式、變數等使用的安全性、可讀性時
  • 在處理較為複雜的數據結構(如多層物件或陣列)時,提高代碼的可讀性和可維護性

The type names String, Number, and Boolean (starting with capital letters) are legal, but refer to some special built-in types that will very rarely appear in your code. Always use string, number, or boolean for types.

官方提到若要使用 String, Number, Boolean 這種大寫開頭的註釋方式是可行的,但不建議使用
原因是大寫會指向 JS 的物件,例如 String 是指向內建的 String 物件,除非你需要取用該物件裡提供的方法,否則寫 string, number, boolean 就好了👍🏻👍🏻👍🏻


型別推斷(Type Inference)

讓 TypeScript 自動推斷型別,可減少定義型別,使 code 更簡潔

使用時機:

  • 當變數的初始值很明顯表明了其型別時
  • 當變數只在區域內使用,且型別容易推斷時
  • 當上下文已經提供了足夠的訊息可以推敲出型別時

範例

1.【型別註釋】當傳入的值不符合定義的型別時,在開發中就會報錯

const playSong = (artistName: string, year: number) => {
  return `In ${year}, everyone love ${artistName}.`;
};

const artist: string = "Lady Gaga"; 
const year: number = 2024;

playSong(artist, year);
playSong('Taylor Swift', '2024'); // ❌ Argument of type 'string' is not assignable to parameter of type 'number'.

2.【型別推斷】當有一個變數的值參雜了多種型別值,TS 會計算出這個變數的「Best common type」。這個範例的「Best common type」會是 numbernull

let x = [0, 1, null];   // let x: (number | null)[]

3.【型別推斷】a 和 b 已經有指定型別,result 為兩者相乘,從上下文可以推斷其型別也會是數字(數字 * 數字 = 數字),所以也沒什麼必要再指定型別

function multiple(a: number, b: number) {
  const result = a * b; // 型別推斷 const result: number
  return result;
}

4.【型別推斷】:「變數宣告」和「變數賦值」兩者分開寫會有不同的結果,先宣告後賦值會被推斷為 :any (any 後續章節會提到)


let a; // 推斷為 :any
a = 1;
a = 2;
a = '3'; // ✅ Pass



let b = 1;
b = 2;
b = '3' // ❌ Type 'string' is not assignable to type 'number'.

結論

  1. 型別註釋」不一定要加好加滿,兩者是可以混用的
  2. 型別註釋」是在程式碼中明確指定型別,提高程式碼可讀性、可維護性
  3. 型別推斷」根據變數的初始值和在上下文中使用的方式,可以自動推斷變數的型別,減少冗長的型別註釋
  4. 型別推斷」可以幫助我們省略「所有的型別註釋」,並非只有省略特定型別

後記

在撰寫這篇文時發現一個有趣的Bug,如下圖
完整錯誤: error TS2451: Cannot redeclare block-scoped variable 'name'.
這支檔案內明明只有變數 name,也沒有自行宣告一樣的全域變數,為何還會跟我說 redeclare 呢?
https://ithelp.ithome.com.tw/upload/images/20240913/201493622lKwb6E8QK.png

這問題的原因是 script 是全域範圍 (global scope),和模組 (module) 不同
想知道詳細解法請看 https://www.jianshu.com/p/78268bd9af0a
TypeScript Github Isues 裡面提到的 moduleDetection 超神!! 在 tsconfig.json 中把它的值改為 force 就正常了/images/emoticon/emoticon24.gif

每天講的內容有推到 github 上喔

References


上一篇
TypeScript 初學者也能看的學習指南 03 - tsconfig.json 的配置
下一篇
TypeScript 初學者也能看的學習指南 05 - Object 物件
系列文
TypeScript 初學者也能看的學習指南16
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言